﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using log4net;
using LumenWorks.Framework.IO.Csv;

namespace MarketData
{
    public class GoogleFinanceAdapter
    {
        private static string urlTemplate = "http://finance.google.com/finance/historical?q={0}&startdate={1}&enddate={1}&output=csv";
        private static readonly ILog Logger =
           LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private Stopwatch stopWatch;
        private readonly string tempDirectory;

        public GoogleFinanceAdapter()
        {
            stopWatch = new Stopwatch();

            // Clean directory where file will be stored
            tempDirectory = Path.Combine(Path.GetTempPath(), "Snap");
            if (Directory.Exists(tempDirectory)) Directory.Delete(tempDirectory, true);
            Directory.CreateDirectory(tempDirectory);
        }

        public decimal GetOpeningPrice( string symbol, DateTime date)
        {
            decimal openingPrice = 0.0m;
            string formattedDate = date.ToString( "MMM+d,+yyyy" );
            var populatedUrl = String.Format( urlTemplate, symbol, formattedDate, formattedDate );
            var fileInfo = DownloadMarketData( populatedUrl );
            if (!fileInfo.Exists)
            {
                Logger.ErrorFormat( "Could not pull opening pricing information with the following URL: {0}",
                                    populatedUrl );
                return openingPrice;
            }
            
            using (var csvReader = new CsvReader( new StreamReader( fileInfo.FullName ), true ))
            {
                // We expect exactly one record
                int numberOfRecords = 0;
                while (csvReader.ReadNextRecord())
                {
                    openingPrice = Decimal.Parse( csvReader[1] );
                    numberOfRecords++;
                }
                if (numberOfRecords > 1)
                {
                    Logger.ErrorFormat( "Returned {0} rows with query {1}", numberOfRecords, populatedUrl );
                }
            }

            return openingPrice;
        }

        /// <summary>
        /// Gets the data.
        /// </summary>
        /// <param name="dataQuery">The info of the temp file.</param>
        private FileInfo DownloadMarketData(string dataQuery)
        {
            var fileInfo = new FileInfo(Path.Combine(tempDirectory, Guid.NewGuid() + ".csv"));
            var request = WebRequest.Create(dataQuery);
            try
            {
                var response = (HttpWebResponse)request.GetResponse();
                if (null == response)
                {
                    const string message = "NULL response from HttpWebResponse getting data.";
                    Logger.Error(message);
                    throw new Exception(message);
                }
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    Logger.ErrorFormat("HTTP Error getting data: {0}", response.StatusCode);
                }

                // Get the data
                stopWatch.Restart();
                using (var reader = new StreamReader(response.GetResponseStream()))
                using (var writer = new StreamWriter(fileInfo.FullName))
                {
                    while (!reader.EndOfStream)
                    {
                        writer.WriteLine(reader.ReadLine());
                    }
                }
                stopWatch.Stop();
                Logger.DebugFormat("Downloaded opening price file (size {0}kb) in {1}",
                                    fileInfo.Length / 1000.0,
                                    stopWatch.Elapsed);
            }
            catch (WebException we)
            {
                // bad request
                Logger.ErrorFormat("Web Exception getting data: {0}", we.Message);
                // read error description from response stream
                if (we.Response != null)
                {
                    using (var reader = new StreamReader(we.Response.GetResponseStream()))
                    {
                        Logger.ErrorFormat("Description: {0}", reader.ReadToEnd());
                    }
                }
            }
            catch (Exception e)
            {
                Logger.ErrorFormat("Exception getting data: {0}", e.Message);
            }

            return (fileInfo);
        }
    }
}
